package ru.chezclif.lern.conread;

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import ru.chezclif.lern.conread.parser.PathDataInputProperties;

/**
 * Наполнение хранилища данных из файла .ini
 * 
 * @author Vit
 */
public class IniParser implements PathDataInputProperties {
	/**
	 * Локальное хранилище настроек
	 */
	private DataBuffer localPropertyBuffer;
	/**
	 * Собранная строка с настройками, созданна для случаев, когда в файле идет разделение одной строки на несколько через спец символ "\" 	 
	 */
	private String multiLine = "";
	/**
	 * Флаг, обозначающий ситуацию, когда в файле, в текущей строке встречается символ "\"
	 */
	private boolean multiLineIgnorRead = false;
	/**
	 * Флаг, обозначающий первую строку в файле
	 */
	private boolean furstLine = true;
	/**
	 * Флаг, обозначающий последнюю строку в файле
	 */
	private boolean endLine = false;
	
	@Override
	/**
	 * По параметру filePath находится файл, из него получают настройки и сохраняют в объект propertyBuffer
	 * 
	 *@param filePath полный путь к оперируемому файлу
	 *@param propertyBuffer хранилище данных для заполнения
	 */
	public void parseFile(String filePath, DataBuffer propertyBuffer) {
		Preconditions.notBlank(filePath);
		Preconditions.notNull(filePath);
		Preconditions.notNull(propertyBuffer);
		this.localPropertyBuffer = propertyBuffer;
		try {
			String standartLine = ""; // переменная для поочередного чтения каждой строки из файла
			String endLineString = ""; // переменная, которая будет содержать последнюю собранную строку
			FileReader fileReader;
			BufferedReader bufferedReader;
			fileReader = new FileReader(filePath);
			bufferedReader = new BufferedReader(fileReader);
			if (!(bufferedReader.ready())) {
				throw new ru.chezclif.lern.conread.exceptions.EmptyFileExeption(filePath);
			}
			// Построчное чтение содержимого файла
			while ((standartLine = bufferedReader.readLine()) != null) {
				if (!multiLineIgnorRead) {
					multiLine = standartLine;
				}
				if (multiLineIgnorRead) {
					multiLine = multiLine + standartLine;
					multiLineIgnorRead = false;
				}
				multiLine = multiLine.trim();
				// Обработка текста подряд разными парсерами
				parseSlash();
				parseComment();
				parseBracket();
				// запись настроек в базу
				if (!(multiLine.equals(""))) {
					parseEquall();
				}
				if (furstLine) {
					furstLine = !furstLine;
				}
				endLineString = standartLine;
			}
			endLine = true;
			parseEndComment(endLineString);
			bufferedReader.close();
			fileReader.close();
		} catch (FileNotFoundException e) {
			throw new ru.chezclif.lern.conread.exceptions.FileNotFoundException(e, filePath);
		} catch (IOException e) {
			throw new ru.chezclif.lern.conread.exceptions.FileNotFoundException(e, filePath);
		}
	}

	/**
	 * Удаление из строк слешей и сборка до целой строки
	 */
	private void parseSlash() {
		for (short i = 0; i < multiLine.length(); i++) {
			if (multiLine.charAt(i) == '\\') {
				if ((i == multiLine.length() - 1)) {
					// Убрать слеш
					multiLine = multiLine.substring(0, multiLine.length() - 1);
					multiLineIgnorRead = true;
				}
			}
		}
	}

	/**
	 * Удаление из строк комментариев
	 */
	private void parseComment() {
		if (!multiLineIgnorRead) {
			for (short i = 0; i < multiLine.length(); i++) {
				if (multiLine.charAt(i) == ';') {
					if (i == 0) {
						parseFurstComment();
						multiLine = "";
					}
					if (i > 0) {
						multiLine = multiLine.substring(0, i - 1);
						break;
					}
				}
			}
		}
	}

	/**
	 * Нахождение головного комментария
	 */
	private void parseFurstComment() {
		if ((furstLine)) {
			this.localPropertyBuffer.setHeaderComment(multiLine.substring(1));
		}
	}

	/**
	 * Нахождение нахождение конечного комментария
	 * 
	 * @param localEndLineString последняя строка, считанная из файла
	 */
	private void parseEndComment(String localEndLineString) {
		if ((endLine) && (localEndLineString.charAt(0) == ';')) {
			this.localPropertyBuffer.setFooterComment(localEndLineString.substring(1));
		}
	}

	/**
	 * Нахождение знака равенства и сохранение найденных настроек
	 */
	private void parseEquall() {
		if (!multiLineIgnorRead) {
			for (short i = 0; i < multiLine.length(); i++) {
				if (multiLine.charAt(i) == '=') {
					this.localPropertyBuffer.setSetting(multiLine.substring(0, i).trim(), multiLine.substring(i + 1, multiLine.length()).trim());
				}
			}
		}
	}

	/**
	 * Удаление из строк скобок и их содержимого
	 */
	private void parseBracket() {
		if (!multiLineIgnorRead) {
			short leftBracketPozition = -1;
			short rightBracketPozition = -1;
			for (short i = 0; i < multiLine.length(); i++) {
				if (multiLine.charAt(i) == '[') {
					leftBracketPozition = i;
				}
				if (multiLine.charAt(i) == ']') {
					rightBracketPozition = i;
				}
			}
			if ((leftBracketPozition < rightBracketPozition) && (!(leftBracketPozition == -1))) {
				multiLine = multiLine.substring(0, leftBracketPozition) + multiLine.subSequence(rightBracketPozition + 1, multiLine.length());
			}
		}
	}
}
